package com.hfjyz.registration.service;

import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;

import cn.com.infosec.icbc.ReturnValue;

import com.hfjyz.registration.command.OrderAnalyzeCommand;
import com.hfjyz.registration.command.OrderInfoPayCommand;
import com.hfjyz.registration.command.OrderInfoPayResultCommand;
import com.hfjyz.registration.command.OrderInfoSearchCommand;
import com.hfjyz.registration.dao.ApplyDao;
import com.hfjyz.registration.dao.OrderInfoDao;
import com.hfjyz.registration.dao.UserDao;
import com.hfjyz.registration.model.Apply;
import com.hfjyz.registration.model.Exam;
import com.hfjyz.registration.model.OrderInfo;
import com.hfjyz.registration.model.User;
import com.hfjyz.registration.object.OrderAnalyzeInfoBean;
import com.hfjyz.registration.task.OrderPaySearchingTask;
import com.hfjyz.registration.task.TaskManager;
import com.hfjyz.registration.util.CryptUtil;
import com.hfjyz.registration.util.ExamProperties;
import com.hfjyz.registration.util.OrderPaySearchFromBank;

public class OrderInfoServiceImpl extends AbstractServiceImpl implements OrderInfoService {

	private UserDao userDao;
	private ApplyDao applyDao;
	private OrderInfoDao orderInfoDao;
	private ExamProperties examProperties;

	/**
	 * @return the userDao
	 */
	public UserDao getUserDao() {
		return userDao;
	}

	/**
	 * @param userDao
	 *            the userDao to set
	 */
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	/**
	 * @return the applyDao
	 */
	public ApplyDao getApplyDao() {
		return applyDao;
	}

	public void setApplyDao(ApplyDao applyDao) {
		this.applyDao = applyDao;
	}

	public OrderInfoDao getOrderInfoDao() {
		return orderInfoDao;
	}

	public void setOrderInfoDao(OrderInfoDao orderInfoDao) {
		this.orderInfoDao = orderInfoDao;
	}

	public ExamProperties getExamProperties() {
		return examProperties;
	}

	public void setExamProperties(ExamProperties examProperties) {
		this.examProperties = examProperties;
	}
	@Override
	public OrderInfo getOrderInfo(String orderId) throws Exception {
		return orderInfoDao.get(orderId);
	}
	@Override
	public void searchOrderInfo(OrderInfoSearchCommand cmd, BindException errors) throws Exception {
		User u = userDao.getByIdCardNo(cmd.getIdCardNo(), cmd.getExam().getId());
		if (u == null) {
			errors.rejectValue("idCardNo", "required.idCardNo", "身份证号不正确!");
			return;
		}
		if (!CryptUtil.encrypt(cmd.getPassword()).equals(u.getPassword())) {
			errors.rejectValue("password", "required.password", "密码不正确!");
			return;
		}
		cmd.setUser(u);
		List<Apply> applyList = applyDao.findApplyInfo(u.getId(), cmd.getExam().getId());
		if (applyList == null || applyList.isEmpty()) {
			errors.rejectValue("idCardNo", "required.apply", "找不到该考生的报名信息");
			return;
		}
		Apply a = applyList.get(0);
		cmd.setApply(a);
		OrderInfo o = orderInfoDao.findByUserIdAndExamId(u.getId(), cmd.getExam().getId());
		cmd.setOrderInfo(o);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Map initOrderPay(OrderInfoPayCommand cmd, Errors errors) throws Exception {
		List<Apply> applyList = applyDao.findApplyInfo(cmd.getUserId(), cmd.getExam().getId());
		if (applyList == null || applyList.isEmpty()) {
			throw new Exception("找不到该考生的报名信息");
		}
		Apply a = applyList.get(0);
		cmd.setApply(a);
		cmd.setUser(a.getUser());
		cmd.setIdCardNo(a.getIdCardNo());

		OrderInfo old = orderInfoDao.findByUserIdAndExamId(cmd.getUserId(), cmd.getExam().getId());
		OrderInfo o = old;
		// 1,3
		if (old == null || old.getOrderState() == 2) {
			// null, 2
			o = makeOrderInfo(cmd.getUser(), cmd.getExam());
			if (old != null) {
				old.setDeleteFlg(true);
				updateOrder(old, false);
				o.setOrderState(old.getOrderState());
			}
			addOrderInfo(o);
			getTranData(a, o, cmd);
		} else if (old.getOrderState() == 0) {
			updateOrder(o, true);
			getTranData(a, o, cmd);
		}
		cmd.setOrderInfo(o);
		cmd.setOrderId(o.getId());
		return null;
	}
	public void searchOrderPayResultFromBank(OrderInfoPayCommand cmd,
			BindException errors) throws Exception {
		OrderInfo o = orderInfoDao.findByUserIdAndExamId(cmd.getUserId(), cmd.getExam().getId());
		int result = OrderPaySearchFromBank.getBankResult(o, examProperties);
		o.setSearchBankCount(o.getSearchBankCount()+1);
		if ("payError".equals(cmd.getSubmitType())) {
			if (result == 1) {
				o.setOrderState(2);
			} else if (result == 2) {
				o.setOrderState(0);
			}
		}
		updateOrder(o, false);
	}
	
	@Transactional
	@Override
	public void updateOrder(OrderInfo o, boolean updateOrderDate) throws Exception {
		if (updateOrderDate) {
			String orderDate = getOrderDate();
			o.setOrderDate(orderDate);
		}
		o.setUpdateDate(new Date());
		orderInfoDao.update(o);
	}

	private String getOrderDate() {
		Date d = new Date();
		DateFormat format2 = new SimpleDateFormat("yyyyMMddHHmmss");
		String orderDate = format2.format(d);
		if (examProperties.isDebug()) {
			orderDate = examProperties.getDebugOrderDate() + orderDate.substring(8);
		}
		return orderDate;
	}

	@Transactional
	public void addOrderInfo(OrderInfo o) throws Exception {
		orderInfoDao.add(o);
	}

	private OrderInfo makeOrderInfo(User u, Exam e) {
		OrderInfo o = new OrderInfo();
		DateFormat format = new SimpleDateFormat("yyMMddHHmmss");
		Date d = new Date();
		o.setId(u.getIdCardNo() + format.format(d));
		o.setOrderDate(getOrderDate());
		o.setUserId(u.getId());
		o.setExamId(e.getId());
		o.setDeleteFlg(false);
		o.setOrderAmount(e.getRegFee());
		o.setOrderState(0); // 未支付
		o.setCreateDate(d);
		o.setUpdateDate(d);
		return o;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Map searchOrderPayResult(OrderInfoPayResultCommand cmd, Errors errors) throws Exception {
		List<Apply> applyList = applyDao.findApplyInfo(cmd.getUserId(), cmd.getExam().getId());
		if (applyList == null || applyList.isEmpty()) {
			throw new Exception("找不到该考生的报名信息");
		}
		Apply a = applyList.get(0);
		cmd.setApply(a);
		cmd.setUser(a.getUser());
		cmd.setIdCardNo(a.getIdCardNo());
		OrderInfo o = orderInfoDao.findByUserIdAndExamId(cmd.getUser().getId(), cmd.getExam().getId());
		cmd.setOrderInfo(o);
		return null;
	};

	@Override
	public void payGoing(OrderInfoPayCommand cmd, BindException errors)
			throws Exception {
		OrderInfo o = orderInfoDao.get(cmd.getOrderId());
		if (o == null) {
			throw new Exception("订单信息不存在");
		}
		o.setOrderState(3); // 支付中
		updateOrder(o, false);
		cmd.setOrderInfo(o);
		cmd.setUserId(o.getUserId());
		
		OrderPaySearchingTask task = new OrderPaySearchingTask(cmd.getOrderId(), this, examProperties);
		new TaskManager(task).start();
	}

	Log log = LogFactory.getLog(getClass());

	private String getTranData(Apply a, OrderInfo o, OrderInfoPayCommand cmd) throws Exception {
		StringBuffer tranData = makePayReqTranData(a, o, cmd);

		encodingData(cmd, tranData);

		cmd.setBankURL(examProperties.getPayBankURL());
		cmd.setInterfaceName("ICBC_PERBANK_B2C");
		cmd.setInterfaceVersion("1.0.0.11");
		return null;
	}

	private StringBuffer makePayReqTranData(Apply a, OrderInfo o, OrderInfoPayCommand cmd) {
		boolean isDebug = examProperties.isDebug();
		StringBuffer tranData = new StringBuffer();
		String merVAR = "userId="+cmd.getUserId()+"&amp;examId=" + cmd.getExam().getId()+"&amp;orderId="+o.getId(); // 返回商户变量
		String customIp = cmd.getMerCustomIp();
		if (isDebug && examProperties.getDebugMerCustomIp() != null
			&& examProperties.getDebugMerCustomIp().length() > 0) {
			customIp = examProperties.getDebugMerCustomIp();
		}
		tranData.append("<?xml version=\"1.0\" encoding=\"GBK\" standalone=\"no\"?>");
		tranData.append("<B2CReq>");
		tranData.append("<interfaceName>").append("ICBC_PERBANK_B2C").append("</interfaceName>");
		tranData.append("<interfaceVersion>").append("1.0.0.11").append("</interfaceVersion>");
		tranData.append("<orderInfo>");
		tranData.append("<orderDate>").append(o.getOrderDate()).append("</orderDate>");
		tranData.append("<curType>001</curType>");
		tranData.append("<merID>").append(examProperties.getPayMerID().trim()).append("</merID>");
		tranData.append("<subOrderInfoList>");
		tranData.append("<subOrderInfo>");
		tranData.append("<orderid>").append(o.getId()).append("</orderid>");
		tranData.append("<amount>").append((int) (cmd.getExam().getRegFee() * 100)).append("</amount>");
		tranData.append("<installmentTimes>").append("1").append("</installmentTimes>");
		tranData.append("<merAcct>").append(examProperties.getPayMerAcct().trim()).append("</merAcct>");
		tranData.append("<goodsID>").append(a.getExamId()).append("</goodsID>");
		tranData.append("<goodsName>").append("笔试费" /*cut(cmd.getExam().getName(), 60)*/).append("</goodsName>");
		tranData.append("<goodsNum>").append("1").append("</goodsNum>");
		tranData.append("<carriageAmt>").append("0").append("</carriageAmt>");
		tranData.append("</subOrderInfo>");
		tranData.append("</subOrderInfoList>");
		tranData.append("</orderInfo>");
		tranData.append("<custom>");
		tranData.append("<verifyJoinFlag>0</verifyJoinFlag>");
		tranData.append("<Language>ZH_CN</Language>");
		tranData.append("</custom>");
		tranData.append("<message>");
		tranData.append("<creditType>2</creditType>");
		tranData.append("<notifyType>AG</notifyType>");
		tranData.append("<resultType>1</resultType>");
		tranData.append("<merReference>").append(examProperties.getPayMerReference()).append("</merReference>");
		tranData.append("<merCustomIp>").append(customIp).append("</merCustomIp>");
		tranData.append("<goodsType>1</goodsType>");
		tranData.append("<merCustomID>").append(cut(a.getUser().getName(), 100)).append("</merCustomID>");
		tranData.append("<merCustomPhone>").append(cut(a.getUser().getTelephone(), 20)).append("</merCustomPhone>");
		tranData.append("<goodsAddress></goodsAddress>");
		tranData.append("<merOrderRemark></merOrderRemark>");
		tranData.append("<merHint></merHint>");
		tranData.append("<remark1></remark1>");
		tranData.append("<remark2></remark2>");
		tranData.append("<merURL>").append(examProperties.getPayMerURL()).append("</merURL>");
		tranData.append("<merVAR>").append(merVAR).append("</merVAR>");
		tranData.append("</message>");
		tranData.append("</B2CReq>");
		return tranData;
	}

	private void encodingData(OrderInfoPayCommand cmd, StringBuffer tranData) throws Exception {
		String password = examProperties.getPayKeyPass(); // 证书密码
		String baseTranData = "";
		String signMsgBase64 = "";
		String certBase64 = "";
		try {
			byte[] byteSrc = tranData.toString().getBytes();
			char[] keyPass = password.toCharArray();

			FileInputStream in1 = new FileInputStream(examProperties.getPayCrtPath());
			byte[] bcert = new byte[in1.available()];
			in1.read(bcert);
			in1.close();
			FileInputStream in2 = new FileInputStream(examProperties.getPayKeyPath());
			byte[] bkey = new byte[in2.available()];
			in2.read(bkey);
			in2.close();

			byte[] sign = ReturnValue.sign(byteSrc, byteSrc.length, bkey, keyPass);
			baseTranData = new String(ReturnValue.base64enc(tranData.toString().getBytes())).toString();
			if (sign == null) {
				throw new Exception("签名失败,签名返回为空。<br>请检查证书私钥和私钥保护口令是否正确。");
			} else {
				log.info("签名成功");

				byte[] EncSign = ReturnValue.base64enc(sign);
				signMsgBase64 = new String(EncSign).toString();
				log.info("签名信息BASE64编码：" + signMsgBase64.substring(0, 100));

				byte[] EncCert = ReturnValue.base64enc(bcert);
				certBase64 = new String(EncCert).toString();
				log.info("证书公钥BASE64编码：" + certBase64.substring(0, 100));

				byte[] DecSign = ReturnValue.base64dec(EncSign);
				if (DecSign != null) {
					log.info("签名信息BASE64解码成功");
					byte[] DecCert = ReturnValue.base64dec(EncCert);
					if (DecCert != null) {
						log.info("证书公钥BASE64解码成功");
						int c = ReturnValue.verifySign(byteSrc, byteSrc.length,
								DecCert, DecSign);
						if (c == 0) {
							log.info("验签成功");
						} else {
							throw new Exception("验签失败 验证返回码：" + c);
						}
					} else {
						throw new Exception("证书BASE64解码失败");
					}
				} else {
					throw new Exception("签名信息BASE64解码失败");
				}
			}

			cmd.setTranData(baseTranData);
			cmd.setMerCert(certBase64);
			cmd.setMerSignMsg(signMsgBase64);
		} catch (Exception e) {
			throw e;
		}
	}

	public String cut(String src, int length) {
		if (src == null) {
			return "";
		}
		return src.length() <= length ? src : src.substring(0, length);
	}

	@Override
	public List<OrderAnalyzeInfoBean> getOrderAnalyzeInfo(
			OrderAnalyzeCommand cmd) throws Exception {
		if (cmd.getAnalyzeType() == null || cmd.getAnalyzeType() == 1) {
			return orderInfoDao.findOrderAnalyzeByExam();
		} else {
			return orderInfoDao.findOrderAnalyzeByOffice(cmd.getExamId());
		}
	}
}
